﻿/************************************************************************

 This file is part of Chroma.

 EscapeFromPrisonPlanet is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 EscapeFromPrisonPlanet is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

************************************************************************/

// All code (c)2013 Scott Bevin. all rights reserved

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace LudumDare26.PrimitiveRendering
{
	public class PEPolygon : PEPrimitive
	{
		public Vector3[] Points;

		public float Width { get { return width; } }

		public float Height { get { return height; } }

		public override int PrimitiveCount { get { return primitiveCount; } }

		// holds the actual vertices for drawing
		private Vector3[] tempArray1;

		private Vector3[] tempArray2;
		private int primitiveCount;
		private float width;
		private float height;
		private int numOfVertices;
		private bool isConvex;

		public PEPolygon(List<Vector2> points)
		{
			float minX = 0f;
			float maxX = 0f;
			float minY = 0f;
			float maxY = 0f;

			Type = PEPrimitiveType.Polygon;
			Points = new Vector3[points.Count];
			tempArray1 = new Vector3[points.Count];
			tempArray2 = new Vector3[points.Count];

			for (int i = 0; i < points.Count; i++)
			{
				Points[i] = new Vector3(points[i], 0);

				// set width and height
				if (minX > points[i].X)
					minX = points[i].X;
				if (maxX < points[i].X)
					maxX = points[i].X;
				if (minY > points[i].Y)
					minY = points[i].Y;
				if (maxY < points[i].Y)
					maxY = points[i].Y;
			}
			width = maxX - minX;
			height = maxY - minY;
			numOfVertices = points.Count;
			isConvex = IsConvex();
			BorderColor = Color.White;
		}

		public bool IsConvex()
		{
			bool isPositive = false;

			for (int i = 0; i < numOfVertices; ++i)
			{
				int lower = (i == 0) ? (numOfVertices - 1) : (i - 1);
				int middle = i;
				int upper = (i == numOfVertices - 1) ? (0) : (i + 1);

				float dx0 = Points[middle].X - Points[lower].X;
				float dy0 = Points[middle].Y - Points[lower].Y;
				float dx1 = Points[upper].X - Points[middle].X;
				float dy1 = Points[upper].Y - Points[middle].Y;

				float cross = dx0 * dy1 - dx1 * dy0;

				// Cross product should have same sign
				// for each vertex if poly is convex.
				bool newIsP = (cross >= 0) ? true : false;
				if (i == 0)
				{
					isPositive = newIsP;
				}
				else if (isPositive != newIsP)
				{
					return false;
				}
			}
			return true;
		}

		public void Decompose(out List<PEPolygon> polygons)
		{
			throw new NotImplementedException();
		}

		public override bool Intersection(PEPrimitive primitive)
		{
			throw new NotImplementedException();
		}

		public override bool Inside(Vector2 point)
		{
			throw new NotImplementedException();
		}

		public override void CreateUV()
		{
			throw new NotImplementedException();
		}

		public override void Draw(ref VertexPositionColorTexture[] vertices, ref int vertexIndex, ref short[] indices, ref int indiceIndex)
		{
			primitiveCount = 0;

			float scaleX = (Width - BorderWidth * 2) / Width;
			float scaleY = (Height - BorderWidth * 2) / Height;

			Matrix mat = Matrix.CreateScale(scaleX, scaleY, 1) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(new Vector3(Position, -Layer));

			Vector3.Transform(Points, ref mat, tempArray2);

			if (isConvex)
			{
				if (IsFilled)
				{
					// simple fan render
					for (int i = 1; i < numOfVertices - 1; i++)
					{
						vertices[vertexIndex].Position = tempArray2[0];
						vertices[vertexIndex].Color = FillColor;
						vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
						vertexIndex++;

						vertices[vertexIndex].Position = tempArray2[i];
						vertices[vertexIndex].Color = FillColor;
						vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
						vertexIndex++;

						vertices[vertexIndex].Position = tempArray2[i + 1];
						vertices[vertexIndex].Color = FillColor;
						vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
						vertexIndex++;

						indices[indiceIndex + 0] = (short)(vertexIndex - 3);
						indices[indiceIndex + 1] = (short)(vertexIndex - 2);
						indices[indiceIndex + 2] = (short)(vertexIndex - 1);

						indiceIndex += 3;

						primitiveCount++;
					}
				}
				if (BorderWidth > 0)
				{
					mat = Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(new Vector3(Position, -Layer));

					Vector3.Transform(Points, ref mat, tempArray1);

					for (int i = 0; i < numOfVertices; i++)
					{
						int index = vertexIndex;

						// 0
						vertices[vertexIndex].Position = tempArray1[i];
						vertices[vertexIndex].Color = BorderColor;
						vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
						vertexIndex++;

						// 1
						vertices[vertexIndex].Position = tempArray2[i];
						vertices[vertexIndex].Color = BorderColor;
						vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
						vertexIndex++;

						// 2
						if (i == numOfVertices - 1)
						{
							vertices[vertexIndex].Position = tempArray1[0];
							vertices[vertexIndex].Color = BorderColor;
							vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
							vertexIndex++;

							// 3
							vertices[vertexIndex].Position = tempArray2[0];
							vertices[vertexIndex].Color = BorderColor;
							vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
							vertexIndex++;
						}
						else
						{
							vertices[vertexIndex].Position = tempArray1[i + 1];
							vertices[vertexIndex].Color = BorderColor;
							vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
							vertexIndex++;

							// 3
							vertices[vertexIndex].Position = tempArray2[i + 1];
							vertices[vertexIndex].Color = BorderColor;
							vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
							vertexIndex++;
						}

						indices[indiceIndex++] = (short)(index + 0);
						indices[indiceIndex++] = (short)(index + 2);
						indices[indiceIndex++] = (short)(index + 1);

						indices[indiceIndex++] = (short)(index + 2);
						indices[indiceIndex++] = (short)(index + 3);
						indices[indiceIndex++] = (short)(index + 1);

						primitiveCount += 2;
					}
				}
			}
		}
	}
}